<!-- 
  - 读取文件组件
 -->

<!--
  - 视图层
 -->
<template>

<!-- 读取数据 -->
<card-comp title="读取数据">
  <!-- 通告栏 -->
  <uni-notice-bar :text="props.noticeText" />

  <!-- 二级标题：快速开始 -->
  <section-comp title="快速开始">
    <!-- 文字内容 -->
    <view>
      　　一键读取示例数据，快速体验功能。
    </view>
    <!-- 读取示例数据 | 数据渲染图 按钮容器 -->
    <view class="center">
      <!-- 读取示例数据 -->
      <button
        v-if="!readFile.isGetFile"
        @click="readExampleData()"
        type="primary" size="mini" :plain="false"
        :disabled="false"
      >
        读取示例数据
      </button>
      <!-- 数据渲染图 -->
      <button
        v-else
        @click="showVisor()"
        type="primary" size="mini" :plain="true"
        :disabled="false"
      >
        查看数据预览图
      </button>
    </view>
  </section-comp>

  <!-- 二级标题：下载示例数据文件 -->
  <section-comp title="示例数据下载">
    <!-- 文字内容 -->
    <view>
      　　操作步骤：<br />
      　　① 下载示例Excel模板文件（示例数据）。<br />
      　　② 根据模板格式，将你自己的数据拷贝至模板。<br />
      　　③ 保存模板文件，然后点击下方的“选择文件”读取你的数据文件即可。
    </view>
    <!-- 示例文件下载按钮 -->
    <view class="center">
      <button
        @click="downloadExampleFile()"
        type="primary" size="mini" :plain="false"
        :disabled="false"
      >
        示例Excel数据文件下载
      </button>
    </view>
  </section-comp>

  <!-- 二级标题：读取数据文件 -->
  <section-comp title="读取数据">
    <!-- 文件上传容器 -->
    <uni-file-picker
      :title="readFile.isGetFile ? '已获得数据' : '点击读取数据文件：'"
      file-extname="xlsx, xls" fileMediatype="all"
      limit="1" return-type="object" :del-icon="false"
      :auto-upload="false" :disable-preview="true"
      :readonly="readFile.isGetFile"
      @select="(event) => { readDataFile(event.tempFiles[0].file) }"
    >
      <!-- 插槽：按钮 -->
      <view class="center">
        <button
          type="primary" size="mini" :plain="false"
          :disabled="false"
        >
          选择文件
        </button>
      </view>
    </uni-file-picker>
  </section-comp>

</card-comp>

</template>

<!--
  - 逻辑层
-->
<script setup>
// 引入各类方法
import { goToPage, downloadFile, wait } from "@/assets/app-utils.js"
import { readXlsxFile, sheetToAoa, aoaTranspose, aoaMapToWorkbook } from "@/assets/app-xlsx.js"
import { showVisor, renderScatterPlot } from "@/assets/app-tfjs-vis.js"
// 引入全局状态管理对象
import { readFileStore } from "@/stores/read-file.js"
// 初始化全局状态管理对象：谱图数据读取状态
const readFile = readFileStore()

// 接收组件传参
const props = defineProps({
  // 公告栏文字内容
  noticeText: { type: String, required: false, default: "打开含有拉曼光谱数据集的Excel文件" },
  // 示例数据的Xlsx文件名
  exampleXlsxName: { type: String, required: false, default: "通用波谱数据集" },
  // 作图的标签
  visTab: { type: String, required: false, default: "原始数据" }
})
// 全局对象：示例数据文件url
const exampleAoaDataUrl = 
  `${ uni.H5_ROUTER_BASE_PATH }static/${ props.exampleXlsxName }.xlsx`

/**
 * 下载示例数据文件
 * @async
 */
async function downloadExampleFile() { try {
  // 显示加载圈
  await uni.loading("正在获取示例数据")
  // 获取示例数据文件Response
  const exampleAoaDataRes = await fetch(exampleAoaDataUrl)
  // 将示例数据文件Response转换为ArrayBuffer
  const exampleAoaDataBuffer = await exampleAoaDataRes.arrayBuffer()
  // 如果示例数据文件ArrayBuffer长度不为1766，则报错
  if (exampleAoaDataBuffer.byteLength ===1766) {
      throw new Error("找不到示例文件，请联系管理员")
  // 否则下载文件
  } else {
    // 隐藏加载圈
    uni.hideLoading()
    downloadFile(exampleAoaDataBuffer, `${ props.exampleXlsxName }.xlsx`)
  }
} catch (error) {
  // 隐藏加载圈
  uni.hideLoading()
  console.error("downloadExampleFile()报错: ", error)
  uni.showModal({
    showCancel: false,
    title: "下载示例数据报错",
    content: error.message,
  })
}}

/**
 * 直接读取示例数据
 * @async
 * 读取示例数据为AOA格式，并赋值给全局状态管理对象readFile.workbook
 */
async function readExampleData() { try {
  // 显示加载圈
  await uni.loading("正在读取数据")
  // 获取示例数据文件
  const exampleAoaDataRes = await fetch(exampleAoaDataUrl)
  // 将示例数据文件转换为workbook格式
  const workbook = await readXlsxFile(exampleAoaDataRes)
  // 绘图
  examplePlot(workbook)
  // 隐藏加载圈
  uni.hideLoading()
  // 打开图表栏
  showVisor()
  // workbook赋值给全局状态管理对象readFile.workbook
  readFile.workbook = workbook
} catch (error) {
  // 隐藏加载圈
  uni.hideLoading()
  console.error("readExampleData()报错: ", error)
  uni.showModal({
    showCancel: false,
    title: "读取示例数据报错",
    content: error.message,
  })
}}

/**
 * 读取数据文件
 * @param { File } file Excel文件对象
 * @note 会写入全局状态管理对象readFile.workbook、readFile.isGetFile
 */
async function readDataFile(file) { try {
  // 显示加载圈
  await uni.loading("正在读取数据")
  // 读取数据文件
  const workbook = await readXlsxFile(file)
  // 绘图
  examplePlot(workbook)
  // 打开图表栏
  showVisor()
  // 隐藏加载圈
  uni.hideLoading()
  // 赋值
  readFile.workbook = workbook
} catch (error) {
  // 隐藏加载圈
  uni.hideLoading()
  console.error("readDataFile()报错: ", error)
  uni.showModal({
    showCancel: false,
    title: "读取数据文件报错",
    content: error.message,
  })
}}

/**
 * 用得到的数据文件绘制示例图片
 * @param { XLSX.WorkBook } workbook Excel工作簿对象
 */
function examplePlot(workbook) { try {
  // 获取工作簿的第1个工作表，转为AOA格式
  const aoa = sheetToAoa(workbook, workbook.SheetNames[0])
  // aoa合法性检查
  if (!aoa[0] || !aoa[0].length) {
    throw new Error("Excel文件为空，请检查")
  }
  // 如果AOA第1行长度为1，即为备注信息，则就地删除AOA第1行的备注
  if (aoa[0].length === 1) {
    aoa.shift()
  }
  // 转置AOA，只要2列数据
  const aoaTransposed = aoaTranspose(aoa, 2)
  // 检测转置AOA第1行以“X”为数组开头，第2行以“Y”或其他不为“X”的值为数组开头
  // 接收转置AOA的第1行、第2行的第1个值，转为字符串，然后去除首尾空格，转为大写字母
  const isX = String(aoaTransposed[0][0]).trim().toUpperCase()
  const isY = String(aoaTransposed[1][0]).trim().toUpperCase()
  // 如果isX不为“X”，或isY居然是“X”，则报错
  if ((isX !== "X") || (isY === "X")) {
    throw new Error("首列数据应标记为“X”，次列数据不应标记为“X”，请检查")
  }
  // 组织数据
  const plotData = {
    // X列去掉“X”
    x: aoaTransposed[0].slice(1),
    // Y列去掉Y
    y: aoaTransposed[1].slice(1),
  }
  // 绘图
  renderScatterPlot(
    { tab: props.visTab, name: "原始数据" },
    [plotData],
    ["首列"]
  )
} catch (error) {
  console.error("examplePlot()报错: ", error)
  // 被调用方法，直接抛出错误即可
  throw new Error(error)
}}

</script>
